﻿using AE_BEPUPhysics_Addition;
using AE_BEPUPhysics_Addition.Interface;
using BEPUphysics.BroadPhaseEntries;
using BEPUutilities;
using FixMath.NET;
using GameConfig;
using GameConfig.weapon;
using GameProtocol;
using System.Collections.Generic;
using TEngine;
using UnityEngine;

namespace GameLogic
{
    public class ShipControl : MonoBehaviour
    {
        AEMeshVolumnBaseCollider m_Collider;
        ShipView m_ShipView;
        ShipDataContainer m_ShipDataContainer;
        Dictionary<int, ShipSlotControl> m_Slots = new Dictionary<int, ShipSlotControl>();
        Influence m_Influence = Influence.Earth;

        public ShipView ShipView { get => m_ShipView; set => m_ShipView = value; }
        public ShipDataContainer ShipData { get => m_ShipDataContainer; }
        public AEMeshVolumnBaseCollider Collider { get => m_Collider; }
        public Influence Influence { get => m_Influence;  }
        #region 静态接口

        static public ShipControl TryGetShipControl(BaseCollider collider)
        {
            return collider.transform?.parent?.parent?.gameObject.GetComponent<ShipControl>();
        }
        static public ShipControl TryGetShipControl(int unityColliderID)
        {

            var collider = FightLogicManager.Instance.GetCollider(unityColliderID);
            if (collider)
            {
                return TryGetShipControl(collider);
            }
            return null;
        }

        #endregion
        #region 生命周期
        public void Awake()
        {
            m_ShipView = GetComponent<ShipView>();
            m_Collider = transform.FindChildComponent<AEMeshVolumnBaseCollider>("Root/LogicBody");
        }
        public void Update()
        {
            m_ShipView.UpdatePosition(m_Collider.transform.position);
            m_ShipView.UpdateRotation(m_Collider.transform.rotation);
            foreach (var i in m_Slots)
            {
                i.Value.Update();
            }
        }
        #endregion
        #region 公开函数
        public void Init(ShipData shipData)
        {
            m_ShipDataContainer = ShipDataContainer.Create(shipData);
            Init();

            BEPUutilities.Vector2 pos = new BEPUutilities.Vector2();
            if (shipData.HasPosX)
                pos.X.RawValue = shipData.PosX;
            if (shipData.HasPosY)
                pos.Y.RawValue = shipData.PosY;
            SetPosition(pos);
        }
        public void Init(int shipID, int instanceID)
        {
            m_ShipDataContainer = ShipDataContainer.Create(shipID, instanceID);
            Init();
        }
        public void Clean()
        {
            m_ShipView.Clean();

            FightLogicManager.Instance.UnregisterCollider(m_Collider);

            foreach(var i in m_Slots)
            {
                i.Value.Clean();
            }
            m_Slots.Clear();
        }
        public void BeDamaged(int damage)
        {
            m_ShipDataContainer.Data.Sp -= damage;
            Debug.Log("ship have be damaged. hp remaind = " + m_ShipDataContainer.Data.Sp);
            if(m_ShipDataContainer.Data.Sp <= 0)
            {
                Explotion();
            }
        }
        public void Explotion()
        {
            FightLogicManager.Instance.UnregisterCollider(m_Collider);
            ShipModule.Instance.PushShipToPool(m_ShipDataContainer.CfgID, this);
        }
        public BEPUutilities.Vector3 GetLogicPosition()
        {
            return m_Collider.GetPosition();
        }
        public BEPUutilities.Quaternion GetLogicRotation()
        {
            return m_Collider.GetOrientation();
        }
        public Vector2Int GetResulution()
        {
            if (m_ShipView == null)
            {
                return Vector2Int.zero;
            }
            return m_ShipView.GetResulution();
        }
        Fix64 m_RotVelocity = 0m;
        BEPUutilities.Vector3 m_MoveVelocity = new BEPUutilities.Vector3();
        BEPUutilities.Vector2 m_MoveDir = new BEPUutilities.Vector2();
        BEPUutilities.Vector2 m_FocusPos = new BEPUutilities.Vector2();
        BEPUutilities.Vector2 m_AimPos = new BEPUutilities.Vector2();
        Fix64 m_AngleDifference = 0;
        bool m_IsFocus = false;
        bool m_IsFire = false;
        public void SetMove(Vector2Int moveDir)
        {
            m_MoveDir = new BEPUutilities.Vector2(moveDir.x / AEUtilities.ToFix64(255), moveDir.y / AEUtilities.ToFix64(255)); ;
        }
        public void SetFocusPosition(Vector2Int focusPos)
        {
            m_FocusPos = new BEPUutilities.Vector2(focusPos.x / (Fix64)1000, focusPos.y / (Fix64)1000);
            m_IsFocus = true;
            //Debug.Log("Angle = " + m_AngleDifference);
        }
        public void SetAimPos(Vector2Int focusPos)
        {
            m_AimPos = new BEPUutilities.Vector2(focusPos.x / (Fix64)1000, focusPos.y / (Fix64)1000);
        }
        public void SetFire(bool fireState)
        {
            m_IsFire = fireState;
        }
        public void SetSkill(bool skillState)
        {
        }
        public void SetPosition(BEPUutilities.Vector2 pos)
        {
            m_Collider.SetPosition(pos);
            m_ShipView.SetPosition(pos);
        }
        public void SetRotation(BEPUutilities.Quaternion quat)
        {
            m_Collider.SetOrientation(quat);
            m_ShipView.SetOrientation(quat);
        }
        public void DoLogic()
        {
            // 移动
            if (m_MoveDir.LengthSquared() > 0)
            {
                var rot = m_Collider.GetOrientation();
                var moveDir = new BEPUutilities.Vector3(m_MoveDir.X * (m_IsFocus ? 1 : 0), m_MoveDir.Y, 0);
                moveDir = BEPUutilities.Quaternion.Transform(moveDir, rot);
                m_MoveVelocity += moveDir * (m_ShipDataContainer.LinearAcceleration * SystemModule.Instance.LogicDelta / 1000);
                if (m_MoveVelocity.LengthSquared() > Fix64.Pow(m_ShipDataContainer.FightVelocityMax / 1000, 2))
                {
                    m_MoveVelocity.Normalize();
                    m_MoveVelocity *= m_ShipDataContainer.FightVelocityMax / 1000;
                }
                var newVelocity = new BEPUutilities.Vector3((m_MoveVelocity.X), (m_MoveVelocity.Y), 0);
                if (m_Collider.GetVelocity() != newVelocity)
                    m_Collider.SetVeolicty(newVelocity);
            }
            else
            {
                m_MoveVelocity = m_Collider.GetVelocity();
            }

            // 旋转
            m_RotVelocity = m_Collider.GetAngularVelocity().Z;
            if (m_IsFocus)
            {
                var selfPos = m_Collider.GetPosition();
                var selfRot = m_Collider.GetOrientation();
                var targetDir = new BEPUutilities.Vector3(m_FocusPos.X, m_FocusPos.Y, 0) - selfPos;
                targetDir.Normalize();
                var curDir = new BEPUutilities.Vector3();
                var upDir = new BEPUutilities.Vector3(0, 1, 0);
                BEPUutilities.Quaternion.Transform(ref upDir, ref selfRot, out curDir);
                var angle = BEPUutilities.Vector3.Angle(curDir, targetDir);
                var crossAxis = BEPUutilities.Vector3.Cross(curDir, targetDir);
                m_AngleDifference = crossAxis.Z > 0 ? angle : -angle;

                var differenceNormalize = m_AngleDifference / Fix64.Abs(m_AngleDifference);
                var rotAcc = differenceNormalize * m_ShipDataContainer.AngularAcceleration / 1000 * SystemModule.Instance.LogicDelta;
                m_RotVelocity += rotAcc;
                //if (rotAcc * m_RotVelocity < 0)
                //    m_RotVelocity = 0;

                Debug.Log("Difference :" + m_AngleDifference + ", normalize: " + differenceNormalize + ", rotAcc = " + rotAcc);
                m_Collider.SetAngularVelocity(new BEPUutilities.Vector3(0, 0, 1) *
                    MathHelper.Clamp(m_RotVelocity * MathHelper.Min(1, Fix64.Abs(m_AngleDifference) / 180m * 10 + 0.5m),
                    //MathHelper.Clamp(m_RotVelocity * MathHelper.Min(1, Fix64.Abs(m_AngleDifference) / 180m * 5 + 0.1m),
                    -m_ShipDataContainer.AngularVelocityMax / 1000, m_ShipDataContainer.AngularVelocityMax / 1000)
                    );
                m_IsFocus = false;
            }
            else if (Fix64.Abs(m_MoveDir.X) > 0)
            {
                m_RotVelocity -= m_MoveDir.X * m_ShipDataContainer.AngularAcceleration / 1000 * SystemModule.Instance.LogicDelta;
                m_Collider.SetAngularVelocity(new BEPUutilities.Vector3(0, 0, 1) *
                    MathHelper.Clamp(m_RotVelocity,
                    -m_ShipDataContainer.AngularVelocityMax / 1000, m_ShipDataContainer.AngularVelocityMax / 1000)
                    );
            }

            foreach (var i in m_Slots)
            {
                i.Value.AimPos(m_AimPos);
                i.Value.SetFire(m_IsFire);
                i.Value.DoLogic();
            }

            m_ShipView.UpdateLogicFrame(m_Collider.transform.position, m_Collider.transform.rotation, m_Collider.transform.localScale);
        }
    #endregion
    #region 私有
        void Init()
        {
            if (m_ShipView == null)
                m_ShipView = gameObject.AddComponent<ShipView>();
            m_ShipView.Init(m_ShipDataContainer);

            var physicsMesh = GlobalFunction.GeneratePhysicsMeshOfSprite(m_ShipView.SpriteRenderer.sprite);
            m_Collider.Mesh = physicsMesh;
            FightLogicManager.Instance.RegisterCollider(m_Collider);

            m_Collider.SetCollisionRole(BEPUphysics.CollisionRuleManagement.CollisionRule.Normal);
            m_Collider.SetLinearDamping(0.8m);
            m_Collider.SetAngularDamping(0.8m);

            m_Slots.Clear();
            foreach (var i in m_ShipDataContainer.ShiDesignData.SlotDesignDatas)
            {
                var slotControle = new ShipSlotControl(this, i.Value);
                if (m_ShipDataContainer.Data.SlotEquipment.ContainsKey(i.Key))
                    slotControle.Init(m_ShipDataContainer.Data.SlotEquipment[i.Key]);
                m_Slots.Add(i.Key, slotControle);
            }
        }
    #endregion
    }
}
